import java.awt.geom.*;
import java.awt.*;
import java.awt.font.TextAttribute;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
class GSpring extends Spring implements Drawable {
   private static final double xPoints[]={0,0.10, 0.125, 0.175, 0.225, 0.275, 0.325, 
                                          0.375, 0.425, 0.475, 0.525,0.575,0.625,
                                          0.675,0.725,0.775,0.825,0.875, 0.90,1.0};
   private static final double yPoints[]={0,0,-0.05,0.05,-0.05,0.05,-0.05,0.05,-0.05,0.05,
                                          -0.05,0.05,-0.05,0.05,-0.05,0.05,-0.05,0.05,0,0};
   private static final Path2D.Double polyline = 
                      new Path2D.Double(Path2D.WIND_EVEN_ODD,xPoints.length);
   private Path2D.Double shape;
   private Stroke stroke;
   private String stiffval;
   private Vector2D freeAendPosition;    // to draw a spring we need
   private Vector2D freeBendPosition;  // extremes well definied
                                     // when it is not connected.

   static {  // static initialization block. It creates a spring of length = 1.
      polyline.moveTo (xPoints[0], yPoints[0]);
      for (int index = 1; index < xPoints.length;index++)
         polyline.lineTo(xPoints[index], yPoints[index]);
   }
   public GSpring(float restLength, float stiffness) {
      super(restLength, stiffness);
      freeAendPosition = new Vector2D(0,0);
      freeBendPosition = new Vector2D(restLength,restLength);
      AffineTransform at = AffineTransform.getTranslateInstance(0,0);
      Vector2D v = getVector();
      at.rotate(v.getX(), v.getY());
      at.scale(v.module(), restLength);
      shape = (Path2D.Double) at.createTransformedShape(polyline);
      stroke = new BasicStroke(0.01f);
   }
   public Vector2D getAendPosition() {
      if (a_end == null)
         return freeAendPosition;
      return super.getAendPosition();
   }
   public Vector2D getBendPosition() {
      if (b_end == null)
         return freeBendPosition;
      return super.getBendPosition();
   }
     /**
    * dibuja en pantalla el objeto spring. recupera el valor de stiffness para desplegarlo
    * en pantalla, dentro de un rectangulo de color negro. Este cambia
    * de tamaño dinamicamente para adaptarse al tamaño del string que representa
    * al stiffness.
    * @param g
    */
   public void draw (Graphics2D g){
      stiffval = ""+get_stiffness();
      Vector2D a=getAendPosition();
      double ax = a.getX();
      double ay = a.getY();
      Vector2D v = getVector();
      AffineTransform at = AffineTransform.getTranslateInstance(ax, ay);
      at.rotate(v.getX(), v.getY());
      at.scale(v.module(),  restLength);
      shape = (Path2D.Double) at.createTransformedShape(polyline);
      if (v.module() < restLength)
         g.setColor(Color.BLACK);
      else
         g.setColor(Color.RED);
      g.setStroke(stroke);
      g.draw(shape);
      g.setColor(Color.BLACK);
      g.fill(new Rectangle2D.Float((float)(v.getX()/2 + ax-0.03),
                                   (float) ((v.getY()/2 + ay)-0.02),
                                   (float) ((stiffval.length()-1)*0.1+0.06),(float)0.15));
      AffineTransform at2 = new AffineTransform();
      at2.scale(0.015, -0.015);
      AttributedString styledText = new AttributedString(stiffval);
      styledText.addAttribute(TextAttribute.FOREGROUND, new Color(0,255,0));
      styledText.addAttribute(TextAttribute.FAMILY,Font.DIALOG_INPUT);
      styledText.addAttribute(TextAttribute.WEIGHT,TextAttribute.WEIGHT_BOLD);
      styledText.addAttribute(TextAttribute.WIDTH,TextAttribute.WIDTH_CONDENSED);
      styledText.addAttribute(TextAttribute.TRANSFORM, at2);
      AttributedCharacterIterator iter = styledText.getIterator();
      g.drawString(iter, (float) (v.getX()/2 + ax),
                         (float) (v.getY()/2 + ay)
                  );

   }
   public boolean contains(double x, double y){
      return shape.getBounds2D().contains(x,y);
   }
   public void dragTo(double x, double y){
      Vector2D a=getAendPosition();
      Vector2D b=getBendPosition();
      double da = Math.abs(a.getX()-x)+Math.abs(a.getY()-y); // "distance" to a
      double db = Math.abs(b.getX()-x)+Math.abs(b.getY()-y); // "distance" to a
      if (da < db) {
         detachAend();
         freeAendPosition.set(x,y);
      }
      else {
         detachBend();
         freeBendPosition.set(x,y);
      }
   }
   public void updateState(){  // just to return to a rest length
      if (a_end==null && b_end==null) return;  // when it is released
      if (a_end!=null) {
         Vector2D v = getVector().unitary().times(restLength);
         freeBendPosition = getAendPosition().plus(v);
         return;
      }
      if (b_end!=null) {
         Vector2D v = getVector().unitary().times(restLength);
         freeAendPosition = getBendPosition().minus(v);
         return;
      }
   }
   public void setSelected() {
      stroke = new BasicStroke(0.03f);
   }
   public void setReleased() {
      stroke = new BasicStroke(0.01f);
   }
}